using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.IO;
using System.Text;
using UnityEngine.Tilemaps;

public class DatabaseCompacting : MonoBehaviour
{
    public Tilemap map;
    public Button btn;
    private string filepath1;
    private string filepath2;

    // Start is called before the first frame update
    void Start()
    {
        filepath1 = @"C:\Users\caomb\Desktop\实训\数据库.txt";
        filepath2 = @"C:\Users\caomb\Desktop\实训\压缩数据库.txt";
        btn.onClick.AddListener(foo);
    }

    void foo()
    {
        Debug.unityLogger.logEnabled = false;
        using(StreamWriter sw = new StreamWriter(filepath2, false)) {
            string[] lines = File.ReadAllLines(filepath1);
            for(int i = 0; i < lines.Length; i+=2) {
                string[] tmp = lines[i].Split();
                int region1 = (int)Convert.ToDouble(tmp[0]);
                int region2 = (int)Convert.ToDouble(tmp[1]);
                sw.WriteLine(region1 + " " + region2);
                string[] _tmp = lines[i+1].Split();
                int index = 0;
                string p = _tmp[index];
                sw.Write(p);
                sw.Write(" ");
                while(index != _tmp.Length-1) {
                    index = BinarySearch(_tmp, p, index);
                    p = _tmp[index];
                    sw.Write(p);
                    if(index != _tmp.Length-1) {
                        sw.Write(" ");
                    }
                }
                sw.Write("\n");
            }
        }
    }

    int BinarySearch(string[] path, string p, int index) {
        int low = index, high = path.Length-1, mid = 0;
        Vector3Int vp1 = ConvertToPoint(p);
        Vector3Int vp2 = new Vector3Int();
        while(low <= high) {
            mid = (low + high) / 2;
            vp2 = ConvertToPoint(path[mid]);
            if(Reachable(vp1, vp2)) {
                low = mid + 1;
            } else {
                high = mid - 1;
            }
        }
        return mid;
    }

    Vector3Int ConvertToPoint(string p) {
        char[] separator = {'(', ',', ')'};
        string[] _p = p.Split(separator);
        int x = (int)Convert.ToDouble(_p[1]);
        int y = (int)Convert.ToDouble(_p[2]);
        Vector3Int vp = new Vector3Int(x, y, 0);
        return vp;
    }

    bool Reachable(Vector3Int p1, Vector3Int p2) {
        Vector3Int p = p1;
        Vector3Int rep = p2;
        while(p != rep) {
            ArrayList list = new ArrayList();
            Vector3Int next = p;
            double f = 999999;
            for(int i = -1; i <= 1; i++) {
                for(int j = -1; j <= 1; j++) {
                    Vector3Int tmp = new Vector3Int(p.x+i, p.y+j, 0);
                    if(map.HasTile(tmp)) {
                        list.Add(tmp);
                    }
                }
            }
            double g = 0, h = 0;
            int offsetX = Math.Abs(rep.x - p.x);
            int offsetY = Math.Abs(rep.y - p.y);
            double square = offsetX * offsetX + offsetY * offsetY;
            double current_h = Math.Pow(square, 0.5);
            for(int i = 0; i < list.Count; i++) {
                Vector3Int tmp = (Vector3Int)list[i];
                offsetX = Math.Abs(p.x - tmp.x);
                offsetY = Math.Abs(p.y - tmp.y);
                square = offsetX * offsetX + offsetY * offsetY;
                g = Math.Pow(square, 0.5);
                offsetX = Math.Abs(rep.x - tmp.x);
                offsetY = Math.Abs(rep.y - tmp.y);
                square = offsetX * offsetX + offsetY * offsetY;
                h = Math.Pow(square, 0.5);
                if(current_h > h && f > g + h) {
                    next = tmp;
                    f = g + h;
                }
            }
            if(p == next) {
                if(p != rep) {
                    return false;
                } else {
                    return true;
                }
            } else {
                p = next;
                if(p == rep) {
                    return true;
                }
            }
        }
        return true;
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}
